#pragma once
#include<iostream>
#include <cstring>
#include <string>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "buffer.h"
#include "log.hpp"

using namespace std;
#define MAX_LISTEN_SIZE 10
class Socket{
    public:
    Socket(){};
    Socket(int fd):_sockfd(fd){};
    ~Socket(){  }
    int GetFd(){
        return _sockfd;
    }
    //创建socket套接字
    bool Creat(){
        _sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(_sockfd<0){
            perror("socket create error");
            return false;
        }
        return true;
    }
    //绑定ip和端口
    bool Bind(const std::string ip,uint16_t port){
        struct sockaddr_in addr;
        memset(&addr,0,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        if(bind(_sockfd,(struct sockaddr*)&addr,sizeof(addr))<0){
            perror("bind error");
            exit(1);
        }
        return true;    
    }
    //监听
    bool Listen(){
        int n=listen(_sockfd,MAX_LISTEN_SIZE);
        if(n<0){
            perror("listen error");
            exit(1);
        }
        return true;
    }
    //server端接受连接
    int Accept(){
        struct sockaddr_in addr;
        socklen_t len=sizeof(addr);
        int connfd=accept(_sockfd,(struct sockaddr*)&addr,&len);
        if(connfd<0){
            perror("accept error");
            exit(1);
        }
        return connfd;
    }
    //client端连接服务器
    int Connect(const std::string ip,uint16_t port){
        struct sockaddr_in addr;
        memset(&addr,0,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        if(connect(_sockfd,(struct sockaddr*)&addr,sizeof(addr))<0){
            perror("connect error");
            return -1;
        }
        return 0;
    }
    bool Send(const std::string& data,int flags=0){
        int n=send(_sockfd,data.c_str(),data.size(),0);
        if(n<0){
            perror("send error");
            return false;
        }
        return true;
    }
    bool Send(const char* data,int flags=0){
        return Send(std::string(data));
    }
    bool NonBlockSend(const std::string& data){
        return Send(data,MSG_DONTWAIT);
    }
    bool NonBlockSend(const char* data){
        return NonBlockSend(std::string(data));
    }
    bool Recv(Buffer& data,int flags=0){
    //bool Recv(std::string& data,int flags=0){
        //cout<<"recv"<<__LINE__<<endl;
        char buf[65536];
        memset(buf,0,sizeof(buf));
        while(true){
            int n=recv(_sockfd,(void*)buf,sizeof(buf),flags);
            if(n<0){
                if(errno=EAGAIN||errno==EINTR){
                    break;
                }
                perror("recv error");
                return false;
            }
            //LOG(ly::LogLevel::DEBUG)<<"recv:"<<std::string(buf,n);
            data.Write(std::string(buf,n));
            if(n<sizeof(buf)){
                break;
            }
        }
        return true;
    }
    //非阻塞接收
    bool NonBlockRecv(Buffer& data){
        return Recv(data,MSG_DONTWAIT);
    }
    //创建服务端套接字
    bool CreateServer(const std::string ip,uint16_t port){
        if(!Creat()) return false;
        if(!Bind(ip,port)) return false;
        if(!Listen()) return false;
        ReuseAddress();
        return true;
    }
    //创建客户端套接字
    bool CreateClient(const std::string& ip,uint16_t port){
        if(!Creat()) return false;
        if(Connect(ip,port)<0) return false;
        return true;
    }
    //设置套接字选项---开启地址端口重用
    void ReuseAddress() {
        // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
        int reuse=1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    }
    bool Close(){
        if(_sockfd>=0){
            LOG(ly::LogLevel::DEBUG)<<"close"<<_sockfd;
            int n=close(_sockfd);
            if(n<0){
                perror("close error");std::cout<<__LINE__<<std::endl;
                return false;
            }
        }
        return true;
    }
    int Fd(){
        return _sockfd;
    }
    private:
        int _sockfd;
};